Last update: Sunday, September 18, 22:12.
This is a Stan implementation of Drew Linzer’s dynamic Bayesian election forecasting model, with some tweaks to incorporate national poll data, pollster house effects, correlated priors on state-by-state election results and comovement of public opinion across states.
For more details on the original model:
Linzer, D. 2013. “Dynamic Bayesian Forecasting of Presidential Elections in the States.” Journal of the American Statistical Association. 108(501): 124-134. (link)
Ten most recently added polls:
| End Date | Source | State | % Clinton | % Trump | N |
|---|---|---|---|---|---|
| 2016-09-16 | Muhlenberg | PA | 55.6 | 44.4 | 292 |
| 2016-09-15 | SoonerPoll | OK | 41.4 | 58.6 | 448 |
| 2016-09-14 | UPI | – | 49.5 | 50.5 | 1202 |
| 2016-09-14 | Opinion Savvy | GA | 47.7 | 52.3 | 500 |
| 2016-09-14 | Monmouth University | IA | 45.1 | 54.9 | 331 |
| 2016-09-14 | Mason | MN | 53.7 | 46.3 | 512 |
| 2016-09-14 | Suffolk | OH | 48.1 | 51.9 | 405 |
| 2016-09-13 | EPIC | MI | 52.1 | 47.9 | 438 |
| 2016-09-13 | Monmouth University | NV | 48.8 | 51.2 | 349 |
| 2016-09-12 | CNN | FL | 47.9 | 52.1 | 756 |
443 polls available since April 01, 2016 (including 355 state polls and 88 national polls).
This graph shows the posterior median (blue line) and 90% credible interval (light grey area) of Hillary Clinton’s share of the national vote, derived from the weighted average of latent state-by-state vote intentions (using the same state weights as in the 2012 presidential election).
\[\pi^{clinton}[t, US] = \sum_{s \in S} \omega_s \cdot \textrm{logit}^{-1} (\mu_a[t] + \mu_b[t, s])\]
From today to November 8, Hillary Clinton’s share of the national vote is predicted to shrink partially towards the Time for Change prior (shown with the dotted black line).
Each national poll is represented as a blue dot. Hillary Clinton’s national poll numbers seem to be running about 1 points below the level that would be consistent with the latent state-by-state vote intentions.
The following graphs show vote intention by state (with 100 draws from the posterior distribution represented as thin grey lines).
\[\pi^{clinton}[t,s] = \textrm{logit}^{-1} (\mu_a[t] + \mu_b[t, s])\]
As expected, credible intervals (light grey areas) are wider for states and periods in which few polls are available and when state polls disagree with each other.
Most pro-Clinton polls:
| Poll Origin | Median | P95 | P05 |
|---|---|---|---|
| Raba Research | 2.4 | 0.5 | 4.6 |
| Public Religion Research Institute | 2.2 | 0.2 | 4.3 |
| Loras College | 2.1 | -0.3 | 4.8 |
| Saint Leo University | 2.1 | -0.1 | 4.5 |
| Siena | 2.1 | 0.2 | 4.1 |
| ICITIZEN | 1.7 | -0.1 | 3.5 |
Most pro-Trump polls:
| Poll Origin | Median | P95 | P05 |
|---|---|---|---|
| Clout Research | -2.6 | -5.3 | -0.4 |
| InsideSources | -2.6 | -5.1 | -0.3 |
| Emerson College Polling Society | -2.0 | -3.8 | -0.3 |
| Rasmussen | -2.0 | -3.0 | -1.0 |
| Hampton University | -1.9 | -4.0 | 0.2 |
| YouGov | -1.8 | -3.9 | 0.2 |
The runmodel.R script downloads .csv files from the Princeton Election Consortium website (which are themselves compiled from the HuffPost Pollster API) before processing the data.
The model ignores third-party candidates and undecided voters. I restrict each poll’s sample to respondents declaring vote intentions for Clinton or Trump, so that \(N = N^{clinton} + N^{trump}\).
When multiple polls are available by the same pollster, at the same date, and for the same state, I pick polls of likely voters rather than registered voters, and polls for which \(N^{clinton} + N^{trump}\) is the smallest (assuming that these are poll questions in which respondents are given the option to choose a third-party candidate, rather than “pushy” questions in which respondents are only asked to choose between the two leading candidates – these polls tend to be less favorable to Hillary Clinton).
No polls are available for the following 1 states: D.C.. These states are left out of the model.
The model is in the file state and national polls.stan. It has a backward component, which aggregates poll history to derive unobserved latent vote intentions; and a forward component, which predicts how these unobserved latent vote intentions will evolve until election day. The backward and forward components are linked through priors about vote intention evolution: in each state, latent vote intentions follow a reverse random walk in which latent vote intentions “start” on election day \(T\) and evolve in random steps (correlated across states) as we go back in time. The starting point of the reverse random walk is the final state of vote intentions, which is assigned a reasonable prior, based on the Time-for-change, fundamentals-based election prediction model. The model reconciles the history of state and national polls with prior beliefs about final election results and about how vote intention evolves.
For each poll \(i\), the number of respondents declaring they intended to vote for Hillary Clinton \(N^{clinton}_i\) is drawn from a binomial distribution:
\[ N^{clinton}_i \sim \textrm{Binomial}(N_i, \pi^{clinton}_i) \]
where \(N_i\) is poll sample size, and \(\pi^{clinton}_i\) is share of the Clinton vote for this poll.
The model treats national and state polls differently.
If poll \(i\) is a state poll, I use a day/state/pollster multilevel model:
\[\textrm{logit} (\pi^{clinton}_i) = \mu_a[t_i] + \mu_b[t_i, s_i] + \mu_c[p_i] + u_i\]
What this model does is simply to decompose the log-odds of reported vote intentions towards Hillary Clinton \(\pi^{clinton}_i\) into a national component, shared across all states (\(\mu_a\)), a state-specific component (\(\mu_b\)), a pollster house effect (\(\mu_c\)), and a measurement noise term (\(u\))
On the day of the last available poll \(t_{last}\), the national swing component \(\mu_a[t_{last}]\) is set to zero, so that the predicted share of the Clinton vote in state \(s\) (net of pollster house effects) after that date and until election day \(T\) is:
\[\pi^{clinton}_{ts} = \textrm{logit}^{-1} (\mu_b[t, s])\]
To reduce the number of parameters, the model only takes weekly values for \(\mu_b\), so that:
\[\mu_b[t, s] = \mu_b^{weekly}[w_t, s]\]
where \(w_t\) is the week of day \(t\).
If poll \(i\) is a national poll, I use the same multilevel approach (with random intercepts for pollster house effects \(\mu_c\)) but I add a little tweak: the share of the Clinton vote in a national poll should also reflect the weighted average of state-by-state scores at the time of the poll. I model the share of vote intentions in national polls in the following way:
\[\textrm{logit} (\pi^{clinton}_i) = \textrm{logit}\left( \sum_{s \in \{1 \dots S\}} \omega_s \cdot \textrm{logit}^{-1} (\mu_a[t_i] + \mu_b^{weekly}[w_{t_i}, s_i]) \right) + \alpha + \mu_c[p_i] + u_i\]
where \(\omega_s\) represents the share of state \(s\) in the total votes of the set of polled states \(1 \dots S\) (based on 2012 turnout numbers). The \(\alpha\) parameter corrects for possible discrepancies between the national vote and the weighted average of state polls. Possible sources of discrepancies may include:
The idea is that while national poll levels may be off and generally not very indicative of the state of the race, national poll changes may contain valuable information to update \(\mu_a\) and (to a lesser extent) \(\mu_b\) parameters.
In order to smoothe out vote intentions by state and obtain latent vote intentions at dates in which no polls were conducted, I use 2 reverse random walk priors for \(\mu_a\) and \(\mu_b^{weekly}\) from \(t_{last}\) to April 1:
\[\mu_b^{weekly}[w_t-1, s] \sim \textrm{Normal}(\mu_b^{weekly}[w_t, s], \sigma_b \cdot \sqrt{7})\]
\[\mu_a[t-1] \sim \textrm{Normal}(\mu_a[t], \sigma_a)\]
\(\sigma_a\) and \(\sigma_b\) are respectively set to 0.012 and 0.006 from April 1 (start of the analysis) to today – these are essentially smoothing parameters. These priors express the belief that the day-to-day standard deviation of latent vote intentions is about 0.3%, and that about 80% of the day-to-day variance in vote intentions is explained by national swings.
I use a multivariate normal distribution for the prior of the final outcome. Its mean is based on the Time-for-Change model – which predicts that Hillary Clinton should receive 48.6% of the national vote (based on Q2 GDP figures, the current President’s approval rating and number of terms). The prior expects state final scores to remain on average centered around \(48.6\% + \delta_s\), where \(\delta_s\) is the excess Obama performance relative to the national vote in 2012 in state \(s\).
\[\mu_b[T, 1 \dots S] \sim \textrm{Multivariate Normal}(\textrm{logit} (0.486 + \delta_{1 \dots S}), \mathbf{\Sigma})\]
For the covariance matrix \(\mathbf{\Sigma}\), I set the variance to 0.05 and the covariance to 0.03 for all states and pairs of states – which corresponds to a correlation coefficient of 0.6 across states.
This prior is relatively imprecise as to the expected final scores in any given state; for example, in a state like Virginia, which Obama won by 52% in 2012 (a score identical to his national score), Hillary Clinton is expected to get 48.6% of the vote, with a 95% certainty that her score will not fall below 38% or exceed 60%.
State scores are also expected to be correlated with each other: according to the prior, there is a 97.8% chance that Hillary Clinton’s score in Virginia will exceed her score in Texas (whereas one would expect this unrealistic scenario to happen with only 90% certainty if the priors were independent). The covariance matrix implies that the correlation between the 2012 and 2016 scores by state is expected to be about 0.95, with 95% confidence that it will be between 0.93 and 0.97 (as opposed to 0.89 [0.84, 0.93] if covariances were set to zero), which is in line with observed correlations in all elections since 1992 [http://election.princeton.edu/2016/06/02/the-realignment-myth/].
To put it differently, the model does not have a very precise prior about final scores, but it does assume that most of this uncertainty is attributable to national-level swings in vote intentions.
From election day to the date of the latest available poll \(t_{last}\), vote intentions by state “start” at \(\mu_b[T,s]\) and follow a random walk with correlated steps across states:
\[\mu_b^{weekly}[w_t-1, 1 \dots S] \sim \textrm{Multivariate Normal}(\mu_b^{weekly}[w_t, 1 \dots S], \mathbf{\Sigma_b^{walk}})\]
I set \(\mathbf{\Sigma_b^{walk}}\) so that all variances equal 0.00118 and all covariances equal 0.00047 (\(\rho =\) 0.4). This implies a 0.3% standard deviation in daily vote intentions changes in a state where Hillary Clinton’s score is close to 50%. To put it differently, the prior is 95% confident that Hillary Clinton’s score in any given state where she is currently polling around 50% should not move up or down by more than 4.5% over the remaining 51 days until the election.
Each pollster \(p\) can be biased towards Clinton or Trump:
\[\mu_c[p] \sim \textrm{Normal}(0, \sigma_c)\]
\[\sigma_c \sim \textrm{Uniform}(0, 0.5)\]
I give the \(\alpha\) parameter a prior centered around the observed distance of polled state voters from the national vote in 2012 (not very useful any more, since all states except DC have been polled at least once):
\[\bar{\delta_S} = \sum_{s \in \{1 \dots S\}} \omega_s \cdot \pi^{obama'12}_s - \pi^{obama'12}\]
\[\alpha \sim \textrm{Normal}(\textrm{logit} (\bar{\delta_S}), 0.2)\]
The noise term \(u_i\) is normally distributed, with standard error \(\sigma_u^{national}\) for national polls, and \(\sigma_u^{state}\) for state polls. I give both standard errors a uniform distribution between 0 and 1.
With 4 chains and 2000 iterations (the first 1000 iterations of each chain are discarded), the model runs in less than 10 minutes on my 4-core Intel i7 MacBookPro.
## [1] "Inference for Stan model: state and national polls."
## [2] "4 chains, each with iter=2000; warmup=1000; thin=1; "
## [3] "post-warmup draws per chain=1000, total post-warmup draws=4000."
## [4] ""
## [5] " mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat"
## [6] "alpha -0.04 0 0.02 -0.07 -0.05 -0.04 -0.03 -0.01 4000 1"
## [7] "sigma_c 0.07 0 0.01 0.05 0.06 0.07 0.07 0.09 1557 1"
## [8] "sigma_u_national 0.04 0 0.01 0.02 0.03 0.04 0.04 0.06 1174 1"
## [9] "sigma_u_state 0.05 0 0.01 0.03 0.05 0.05 0.06 0.07 1172 1"
## [10] "mu_b[31,2] -0.28 0 0.11 -0.48 -0.35 -0.28 -0.21 -0.07 4000 1"
## [11] "mu_b[31,3] -0.52 0 0.11 -0.73 -0.59 -0.52 -0.45 -0.31 4000 1"
## [12] "mu_b[31,4] -0.36 0 0.10 -0.56 -0.43 -0.36 -0.29 -0.16 4000 1"
## [13] "mu_b[31,5] -0.13 0 0.09 -0.31 -0.19 -0.13 -0.06 0.06 4000 1"
## [14] "mu_b[31,6] 0.48 0 0.09 0.30 0.42 0.48 0.54 0.67 4000 1"
## [15] "mu_b[31,7] 0.09 0 0.10 -0.10 0.02 0.09 0.15 0.28 4000 1"
## [16] "mu_b[31,8] 0.24 0 0.10 0.06 0.18 0.24 0.31 0.43 4000 1"
## [17] "mu_b[31,9] 0.30 0 0.10 0.10 0.23 0.30 0.37 0.50 4000 1"
## [18] "mu_b[31,10] 0.00 0 0.09 -0.18 -0.06 0.00 0.07 0.18 4000 1"
## [19] "mu_b[31,11] -0.12 0 0.09 -0.30 -0.18 -0.12 -0.06 0.06 4000 1"
## [20] "mu_b[31,12] 0.79 0 0.12 0.56 0.71 0.79 0.87 1.02 4000 1"
## [21] "mu_b[31,13] -0.02 0 0.09 -0.21 -0.09 -0.02 0.04 0.16 4000 1"
## [22] "mu_b[31,14] -0.64 0 0.11 -0.85 -0.71 -0.64 -0.57 -0.43 4000 1"
## [23] "mu_b[31,15] 0.36 0 0.10 0.17 0.29 0.36 0.43 0.55 4000 1"
## [24] "mu_b[31,16] -0.35 0 0.10 -0.53 -0.41 -0.35 -0.28 -0.16 4000 1"
## [25] "mu_b[31,17] -0.34 0 0.10 -0.53 -0.40 -0.34 -0.27 -0.15 4000 1"
## [26] "mu_b[31,18] -0.55 0 0.12 -0.78 -0.63 -0.55 -0.48 -0.33 4000 1"
## [27] "mu_b[31,19] -0.36 0 0.10 -0.55 -0.42 -0.36 -0.29 -0.16 4000 1"
## [28] "mu_b[31,20] 0.52 0 0.10 0.33 0.45 0.52 0.58 0.71 4000 1"
## [29] "mu_b[31,21] 0.63 0 0.10 0.43 0.56 0.63 0.70 0.83 4000 1"
## [30] "mu_b[31,22] 0.17 0 0.09 -0.02 0.10 0.17 0.23 0.35 4000 1"
## [31] "mu_b[31,23] 0.10 0 0.09 -0.08 0.04 0.10 0.16 0.28 4000 1"
## [32] "mu_b[31,24] 0.15 0 0.10 -0.04 0.08 0.15 0.22 0.34 4000 1"
## [33] "mu_b[31,25] -0.19 0 0.09 -0.37 -0.25 -0.19 -0.12 -0.01 4000 1"
## [34] "mu_b[31,26] -0.15 0 0.11 -0.36 -0.22 -0.15 -0.07 0.07 4000 1"
## [35] "mu_b[31,27] -0.34 0 0.11 -0.55 -0.41 -0.33 -0.26 -0.13 4000 1"
## [36] "mu_b[31,28] -0.01 0 0.09 -0.19 -0.07 -0.01 0.05 0.16 4000 1"
## [37] "mu_b[31,29] -0.57 0 0.12 -0.79 -0.65 -0.56 -0.49 -0.34 4000 1"
## [38] "mu_b[31,30] -0.36 0 0.11 -0.57 -0.43 -0.36 -0.28 -0.14 4000 1"
## [39] "mu_b[31,31] 0.09 0 0.09 -0.09 0.03 0.09 0.15 0.27 4000 1"
## [40] "mu_b[31,32] 0.29 0 0.10 0.11 0.23 0.29 0.36 0.48 4000 1"
## [41] "mu_b[31,33] 0.22 0 0.10 0.03 0.16 0.22 0.29 0.41 4000 1"
## [42] "mu_b[31,34] 0.03 0 0.09 -0.16 -0.03 0.03 0.09 0.21 4000 1"
## [43] "mu_b[31,35] 0.44 0 0.09 0.25 0.37 0.44 0.50 0.63 4000 1"
## [44] "mu_b[31,36] 0.00 0 0.09 -0.18 -0.06 0.00 0.06 0.19 4000 1"
## [45] "mu_b[31,37] -0.62 0 0.10 -0.81 -0.69 -0.62 -0.55 -0.42 4000 1"
## [46] "mu_b[31,38] 0.26 0 0.10 0.07 0.19 0.26 0.32 0.45 4000 1"
## [47] "mu_b[31,39] 0.10 0 0.09 -0.08 0.04 0.10 0.16 0.27 4000 1"
## [48] "mu_b[31,40] 0.36 0 0.11 0.14 0.29 0.36 0.44 0.58 4000 1"
## [49] "mu_b[31,41] -0.19 0 0.10 -0.37 -0.25 -0.19 -0.12 0.01 4000 1"
## [50] "mu_b[31,42] -0.40 0 0.11 -0.61 -0.47 -0.40 -0.32 -0.18 4000 1"
## [51] "mu_b[31,43] -0.44 0 0.10 -0.64 -0.51 -0.44 -0.37 -0.23 4000 1"
## [52] "mu_b[31,44] -0.19 0 0.09 -0.38 -0.25 -0.19 -0.13 0.00 4000 1"
## [53] "mu_b[31,45] -0.54 0 0.10 -0.73 -0.61 -0.55 -0.48 -0.35 4000 1"
## [54] "mu_b[31,46] 0.12 0 0.09 -0.06 0.05 0.12 0.18 0.30 4000 1"
## [55] "mu_b[31,47] 0.71 0 0.11 0.50 0.64 0.71 0.79 0.93 4000 1"
## [56] "mu_b[31,48] 0.30 0 0.10 0.10 0.23 0.30 0.37 0.49 4000 1"
## [57] "mu_b[31,49] 0.10 0 0.09 -0.08 0.04 0.10 0.16 0.27 4000 1"
## [58] "mu_b[31,50] -0.63 0 0.10 -0.83 -0.70 -0.63 -0.56 -0.42 4000 1"
## [59] "mu_b[31,51] -0.98 0 0.11 -1.20 -1.06 -0.98 -0.91 -0.76 4000 1"
## [60] ""
## [61] "Samples were drawn using NUTS(diag_e) at Sun Sep 18 22:12:06 2016."
## [62] "For each parameter, n_eff is a crude measure of effective sample size,"
## [63] "and Rhat is the potential scale reduction factor on split chains (at "
## [64] "convergence, Rhat=1)."
These are the median values for \(\mu_a\) (in red) and \(\mu_b\) (in grey) parameters: